from abc import ABCMeta, abstractmethod

"""
定义一个操作算法中的框（骨）架,而将算法中用到的某些具体的步骤放在子类中实现，使得子类可以在不改变算法结构的情况下重新定义
该算法的某些特定步骤。这个定义算法骨架的方法就叫模板方法模式，简称模板模式。

应用场景：
1、对一些复杂的算法进行分割，将其算法中固定不变的部分设计为模板方法和父类具体方法，而一些可以改变的细节有子类来实现。
2、各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。
3、需要通过子类来决定父类算法中某个步骤是否执行，实现子类对父类的反向控制。
"""
class Template(metaclass=ABCMeta):
    """模板类（抽象类）"""
    @abstractmethod
    def stepOne(self):
        pass

    @abstractmethod
    def stepTwo(self):
        pass

    @abstractmethod
    def stepThree(self):
        pass

    def templateMethod(self):
        """模板方法"""
        self.stepOne()
        self.stepTwo()
        self.stepTwo()


class TemplateImplA(Template):
    """模板实现类A"""
    def stepOne(self):
        print("步骤一")

    def stepTwo(self):
        print("步骤二")

    def stepThree(self):
        print("步骤三")


class TemplateImplB(Template):
    """模板实现类B"""
    def stepOne(self):
        print("Step one")

    def stepTwo(self):
        print("Step two")

    def stepThree(self):
        print("Step three")


class ReaderView(metaclass=ABCMeta):
    """阅读器视图"""
    def __init__(self):
        self.__curPageNum = 1

    def getPage(self, pageNum):
        self.__curPageNum = pageNum
        return "第" + str(pageNum) + "页的内容"

    def prePage(self):
        """模板方法，往前翻一页"""
        content = self.getPage(self.__curPageNum - 1)
        self._displayPage(content)

    def nextPage(self):
        """模板方法，往后翻一页"""
        content = self.getPage(self.__curPageNum + 1)
        self._displayPage(content)

    @abstractmethod
    def _displayPage(self, content):
        """翻页效果"""
        pass


class SmoothView(ReaderView):
    """左右平滑的视图"""
    def _displayPage(self, content):
        print("左右平滑：" + content)


class SimulationView(ReaderView):
    """仿真翻页的视图"""
    def _displayPage(self, content):
        print("仿真翻页：" + content)

def testReader():
    smoothView = SmoothView()
    smoothView.nextPage()
    smoothView.prePage()

    simulationView = SimulationView()
    simulationView.nextPage()
    simulationView.prePage()


if __name__ == "__main__":
    testReader()